﻿using Grow.EventBus.Cap.SubscriberDomainEvents;
using Grow.Json;
using Grow.Module.Service;
using Grow.Module.Thread;
using Grow.Utils.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Grow.EventBus.Cap.DomainEventHandlerInvoker
{
    public class DomainEventHandlerInvoker : IDomainEventHandlerInvoker
    {
        private readonly IServiceContext _serviceContext;
        private readonly IJsonContext _jsonContext;
        private readonly ICancellationTokenContext cancellationTokenContext ;
        public DomainEventHandlerInvoker(IServiceContext serviceContext)
        {
            _serviceContext = serviceContext;
            _jsonContext= _serviceContext.GetRequiredService<IJsonContext>();
            cancellationTokenContext = _serviceContext.GetRequiredService<ICancellationTokenContext>();
        }
        public async  Task InvokerAsync(SubscriberDomainEventDto subscriberDomainEventDto, CancellationToken cancellationToken = default)
        {
            var eventType = Type.GetType(subscriberDomainEventDto.EventType);
            if (eventType is null)
            {
                throw new GrowCheckException($"{nameof(subscriberDomainEventDto.EventType)} is not null");
            }

            var eventHandlerType = Type.GetType(subscriberDomainEventDto.EventHandlerType);
            if (eventHandlerType is null)
            {
                throw new GrowCheckException($"{nameof(eventHandlerType)} is not null");
            }
            object eventHandler = _serviceContext.GetRequiredService(eventHandlerType);
          
            var eventBody = _jsonContext.DeserializeAsync(subscriberDomainEventDto.EventBody, eventType, cancellationToken);
            if (eventBody is null)
            {
                throw new GrowCheckException($"{nameof(eventBody)} is not null");
            }
            var method = eventHandlerType.GetMethod("ExecuteAsync", new Type[] {
                eventType,typeof(CancellationToken) });
            var task = (Task?)method!.Invoke(eventHandler, new object[] { eventBody, cancellationTokenContext.Token });
            await task!;
        }
    }
}

